#ifndef TB_REFLECTION_REFLECTION_FUNCTION_HPP__
#define TB_REFLECTION_REFLECTION_FUNCTION_HPP__

#include <stack>

#include "tbcore/base/assert.hpp"
#include "tbcore/base/logging.hpp"

#include "type_traits.hpp"
#include "reflection_fwd.hpp"
#include "variant.hpp"

TB_NAMESPACE_BEGIN

namespace reflection {																	

typedef enum {
	kRawFunctor,
	kMenFunctor,
} FunctionType;

struct Function {
	Function(const TCHAR* name_, const TCHAR* param_, const TCHAR* prototype_)
	: name(name_), param(param_), prototype(prototype_) {}

  virtual uint32 GetArgCount() const { return 0; };
  virtual uint32 GetRetType() const { return 0; };
  virtual uint32 GetArgType(uint8 argIdx) const { return 0; };
  virtual const void *GetFunctorData() const = 0;
  virtual bool IsMemberFunction() const = 0;
  virtual void BindObject(void* obj) const { (void)obj; };
  virtual Variant InvokeWithRet(const std::stack<Variant>& params) const = 0;
  virtual void InvokeWithoutRet(const std::stack<Variant>& params) const = 0;

  TB_INLINE bool HasRetValue() const { return GetRetType() > 0; }
 

  Variant operator()() const;
  Variant operator()(const Variant& p1) const;
  Variant operator()(const Variant& p1, const Variant& p2) const;
  Variant operator()(const Variant& p1, const Variant& p2, const Variant& p3) const;
  Variant operator()(const Variant& p1, const Variant& p2, const Variant& p3, const Variant& p4) const;
  Variant operator()(const Variant& p1, const Variant& p2, const Variant& p3, const Variant& p4, const Variant& p5) const;
  Variant operator()(const Variant& p1, const Variant& p2, const Variant& p3, const Variant& p4, const Variant& p5, const Variant& p6) const;
  Variant operator()(const Variant& p1, const Variant& p2, const Variant& p3, const Variant& p4, const Variant& p5, const Variant& p6, const Variant& p7) const;

	String name;
  String param;
  String prototype;
};

template <typename FunctorType, typename Enable = void>
struct MakeFunctionHelper {
  static Function* Make(FunctorType fn, const TCHAR* name, const TCHAR* param) {
    return MakeRawFunction(fn, name, param);
  }
};

template <typename FunctorType> struct 
MakeFunctionHelper<FunctorType, typename enable_if<is_member_function_pointer<FunctorType>::value >::type > {
  static Function* Make(FunctorType fn, const TCHAR* name, const TCHAR* param) {
    return MakeMemFunction(fn, name, param);
  }
};

template <typename FunctorType>
Function* MakeFunction(FunctorType fn, const TCHAR* name = _T(""), const TCHAR* param = _T("")) {
	return MakeFunctionHelper<FunctorType>::Make(fn, name, param);
}

#define __TB_POP_PARAM(INDEX) \
	  std::unique_ptr<Param##INDEX##Type_, null_deleter> t##INDEX; \
		const Variant &p##INDEX = params_.top(); \
		if (p##INDEX.IsReference()) { \
			t##INDEX = std::unique_ptr<Param##INDEX##Type_, null_deleter>(p##INDEX.UnRef<Param##INDEX##Type_>(), null_deleter(false)); \
		} else { \
			t##INDEX## = std::unique_ptr<Param##INDEX##Type_, null_deleter>(new Param##INDEX##Type_(p##INDEX.Value<Param##INDEX##Type_>()), null_deleter(true));  \
		} \
		params_.pop();

#define __TB_TYPEDEF_PARAM_TYPE(INDEX) \
  typedef typename remove_crv<Param##INDEX##Type>::type Param##INDEX##Type_;

#define __TB_GEN_GET_PARAM_TYPE_CASE(INDEX) \
  case INDEX: { \
    return GetVariantTypeId<Param##INDEX##Type_>(); \
  }

#define __TB_IMPLEMENT_MEM_FUNCTION_VARIADICS

#define __TB_PARAM_LIST
#define __TB_PASS_PARAM_LIST
#define __TB_PASS_PARAM_LIST_WITH_COMMA
#define __TB_TYPEDEF_TYPES_BLOCK
#define __TB_POP_PARAMS_BLOCK
#define __TB_GET_PARAM_TYPE_CASES 
#define __TB_PARAM_WITH_NAME_LIST
#define __TB_RETRIVE_PARAM_VALUE_LIST 
#define __TB_PASS_PARAM_VALUS_LIST 
#define __TB_PARAM_COUNT 0
#define __TB_IS_RAW_FUNCTOR 0
#define __TB_VARIADICS_CLASS_PREFIX ZeroParam
#define __TB_NO_CASE
#include "funtion_impl_variadics.inl"
#undef __TB_IS_RAW_FUNCTOR
#define __TB_IS_RAW_FUNCTOR 1
#include "funtion_impl_variadics.inl"
#undef __TB_PARAM_LIST
#undef __TB_PASS_PARAM_LIST
#undef __TB_PASS_PARAM_LIST_WITH_COMMA
#undef __TB_TYPEDEF_TYPES_BLOCK
#undef __TB_POP_PARAMS_BLOCK
#undef __TB_GET_PARAM_TYPE_CASES 
#undef __TB_PARAM_WITH_NAME_LIST
#undef __TB_RETRIVE_PARAM_VALUE_LIST 
#undef __TB_PASS_PARAM_VALUS_LIST 
#undef __TB_PARAM_COUNT
#undef __TB_IS_RAW_FUNCTOR
#undef __TB_VARIADICS_CLASS_PREFIX
#undef __TB_NO_CASE

#define __TB_PARAM_LIST , typename Param1Type
#define __TB_PASS_PARAM_LIST Param1Type
#define __TB_PASS_PARAM_LIST_WITH_COMMA , __TB_PASS_PARAM_LIST
#define __TB_TYPEDEF_TYPES_BLOCK __TB_TYPEDEF_PARAM_TYPE(1)
#define __TB_POP_PARAMS_BLOCK __TB_POP_PARAM(1)
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1)
#define __TB_PARAM_WITH_NAME_LIST ,Param1Type_ *t1
#define __TB_RETRIVE_PARAM_VALUE_LIST *t1
#define __TB_PASS_PARAM_VALUS_LIST , t1
#define __TB_PARAM_COUNT 1
#define __TB_IS_RAW_FUNCTOR 0
#define __TB_VARIADICS_CLASS_PREFIX OneParam
#include "funtion_impl_variadics.inl"
#undef __TB_IS_RAW_FUNCTOR
#define __TB_IS_RAW_FUNCTOR 1
#include "funtion_impl_variadics.inl"
#undef __TB_PARAM_LIST
#undef __TB_PASS_PARAM_LIST
#undef __TB_PASS_PARAM_LIST_WITH_COMMA
#undef __TB_TYPEDEF_TYPES_BLOCK
#undef __TB_POP_PARAMS_BLOCK
#undef __TB_GET_PARAM_TYPE_CASES 
#undef __TB_PARAM_WITH_NAME_LIST
#undef __TB_RETRIVE_PARAM_VALUE_LIST 
#undef __TB_PASS_PARAM_VALUS_LIST 
#undef __TB_PARAM_COUNT
#undef __TB_IS_RAW_FUNCTOR
#undef __TB_VARIADICS_CLASS_PREFIX

#define __TB_PARAM_LIST , typename Param1Type, typename Param2Type
#define __TB_PASS_PARAM_LIST Param1Type, Param2Type
#define __TB_PASS_PARAM_LIST_WITH_COMMA , __TB_PASS_PARAM_LIST
#define __TB_TYPEDEF_TYPES_BLOCK __TB_TYPEDEF_PARAM_TYPE(1) __TB_TYPEDEF_PARAM_TYPE(2)
#define __TB_POP_PARAMS_BLOCK __TB_POP_PARAM(2) __TB_POP_PARAM(1)
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1) __TB_GEN_GET_PARAM_TYPE_CASE(2)
#define __TB_PARAM_WITH_NAME_LIST ,Param1Type_ *t1, Param2Type_ *t2
#define __TB_RETRIVE_PARAM_VALUE_LIST *t1, *t2
#define __TB_PASS_PARAM_VALUS_LIST , t1, t2
#define __TB_PARAM_COUNT 2
#define __TB_IS_RAW_FUNCTOR 0
#define __TB_VARIADICS_CLASS_PREFIX TwoParam
#include "funtion_impl_variadics.inl"
#undef __TB_IS_RAW_FUNCTOR
#define __TB_IS_RAW_FUNCTOR 1
#include "funtion_impl_variadics.inl"
#undef __TB_PARAM_LIST
#undef __TB_PASS_PARAM_LIST
#undef __TB_PASS_PARAM_LIST_WITH_COMMA
#undef __TB_TYPEDEF_TYPES_BLOCK
#undef __TB_POP_PARAMS_BLOCK
#undef __TB_GET_PARAM_TYPE_CASES 
#undef __TB_PARAM_WITH_NAME_LIST
#undef __TB_RETRIVE_PARAM_VALUE_LIST 
#undef __TB_PASS_PARAM_VALUS_LIST 
#undef __TB_PARAM_COUNT
#undef __TB_IS_RAW_FUNCTOR
#undef __TB_VARIADICS_CLASS_PREFIX

#define __TB_PARAM_LIST , typename Param1Type, typename Param2Type, typename Param3Type
#define __TB_PASS_PARAM_LIST Param1Type, Param2Type, Param3Type
#define __TB_PASS_PARAM_LIST_WITH_COMMA , __TB_PASS_PARAM_LIST
#define __TB_TYPEDEF_TYPES_BLOCK __TB_TYPEDEF_PARAM_TYPE(1) __TB_TYPEDEF_PARAM_TYPE(2) __TB_TYPEDEF_PARAM_TYPE(3)
#define __TB_POP_PARAMS_BLOCK __TB_POP_PARAM(3) __TB_POP_PARAM(2) __TB_POP_PARAM(1)
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1) __TB_GEN_GET_PARAM_TYPE_CASE(2) __TB_GEN_GET_PARAM_TYPE_CASE(3)
#define __TB_PARAM_WITH_NAME_LIST ,Param1Type_ *t1, Param2Type_ *t2, Param3Type_ *t3
#define __TB_RETRIVE_PARAM_VALUE_LIST *t1, *t2, *t3
#define __TB_PASS_PARAM_VALUS_LIST , t1, t2, t3
#define __TB_PARAM_COUNT 3
#define __TB_IS_RAW_FUNCTOR 0
#define __TB_VARIADICS_CLASS_PREFIX ThreeParam
#include "funtion_impl_variadics.inl"
#undef __TB_IS_RAW_FUNCTOR
#define __TB_IS_RAW_FUNCTOR 1
#include "funtion_impl_variadics.inl"
#undef __TB_PARAM_LIST
#undef __TB_PASS_PARAM_LIST
#undef __TB_PASS_PARAM_LIST_WITH_COMMA
#undef __TB_TYPEDEF_TYPES_BLOCK
#undef __TB_POP_PARAMS_BLOCK
#undef __TB_GET_PARAM_TYPE_CASES 
#undef __TB_PARAM_WITH_NAME_LIST
#undef __TB_RETRIVE_PARAM_VALUE_LIST 
#undef __TB_PASS_PARAM_VALUS_LIST 
#undef __TB_PARAM_COUNT
#undef __TB_IS_RAW_FUNCTOR
#undef __TB_VARIADICS_CLASS_PREFIX

#define __TB_PARAM_LIST , typename Param1Type, typename Param2Type, typename Param3Type, typename Param4Type
#define __TB_PASS_PARAM_LIST Param1Type, Param2Type, Param3Type, Param4Type
#define __TB_PASS_PARAM_LIST_WITH_COMMA , __TB_PASS_PARAM_LIST
#define __TB_TYPEDEF_TYPES_BLOCK __TB_TYPEDEF_PARAM_TYPE(1) __TB_TYPEDEF_PARAM_TYPE(2) __TB_TYPEDEF_PARAM_TYPE(3) __TB_TYPEDEF_PARAM_TYPE(4)
#define __TB_POP_PARAMS_BLOCK __TB_POP_PARAM(4) __TB_POP_PARAM(3) __TB_POP_PARAM(2) __TB_POP_PARAM(1)
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1) __TB_GEN_GET_PARAM_TYPE_CASE(2) __TB_GEN_GET_PARAM_TYPE_CASE(3) __TB_GEN_GET_PARAM_TYPE_CASE(4)
#define __TB_PARAM_WITH_NAME_LIST ,Param1Type_ *t1, Param2Type_ *t2, Param3Type_ *t3, Param4Type_ *t4
#define __TB_RETRIVE_PARAM_VALUE_LIST *t1, *t2, *t3, *t4
#define __TB_PASS_PARAM_VALUS_LIST , t1, t2, t3, t4
#define __TB_PARAM_COUNT 4
#define __TB_IS_RAW_FUNCTOR 0
#define __TB_VARIADICS_CLASS_PREFIX FourParam
#include "funtion_impl_variadics.inl"
#undef __TB_IS_RAW_FUNCTOR
#define __TB_IS_RAW_FUNCTOR 1
#include "funtion_impl_variadics.inl"
#undef __TB_PARAM_LIST
#undef __TB_PASS_PARAM_LIST
#undef __TB_PASS_PARAM_LIST_WITH_COMMA
#undef __TB_TYPEDEF_TYPES_BLOCK
#undef __TB_POP_PARAMS_BLOCK
#undef __TB_GET_PARAM_TYPE_CASES 
#undef __TB_PARAM_WITH_NAME_LIST
#undef __TB_RETRIVE_PARAM_VALUE_LIST 
#undef __TB_PASS_PARAM_VALUS_LIST 
#undef __TB_PARAM_COUNT
#undef __TB_IS_RAW_FUNCTOR
#undef __TB_VARIADICS_CLASS_PREFIX

#define __TB_PARAM_LIST , typename Param1Type, typename Param2Type, typename Param3Type, typename Param4Type, typename Param5Type
#define __TB_PASS_PARAM_LIST Param1Type, Param2Type, Param3Type, Param4Type, Param5Type
#define __TB_PASS_PARAM_LIST_WITH_COMMA , __TB_PASS_PARAM_LIST
#define __TB_TYPEDEF_TYPES_BLOCK __TB_TYPEDEF_PARAM_TYPE(1) __TB_TYPEDEF_PARAM_TYPE(2) __TB_TYPEDEF_PARAM_TYPE(3) __TB_TYPEDEF_PARAM_TYPE(4) __TB_TYPEDEF_PARAM_TYPE(5)
#define __TB_POP_PARAMS_BLOCK __TB_POP_PARAM(5) __TB_POP_PARAM(4) __TB_POP_PARAM(3) __TB_POP_PARAM(2) __TB_POP_PARAM(1)
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1) __TB_GEN_GET_PARAM_TYPE_CASE(2) __TB_GEN_GET_PARAM_TYPE_CASE(3) __TB_GEN_GET_PARAM_TYPE_CASE(4) __TB_GEN_GET_PARAM_TYPE_CASE(5)  
#define __TB_PARAM_WITH_NAME_LIST ,Param1Type_ *t1, Param2Type_ *t2, Param3Type_ *t3, Param4Type_ *t4, Param5Type_* t5
#define __TB_RETRIVE_PARAM_VALUE_LIST *t1, *t2, *t3, *t4, *t5
#define __TB_PASS_PARAM_VALUS_LIST , t1, t2, t3, t4, t5
#define __TB_PARAM_COUNT 5
#define __TB_IS_RAW_FUNCTOR 0
#define __TB_VARIADICS_CLASS_PREFIX FiveParam
#include "funtion_impl_variadics.inl"
#undef __TB_IS_RAW_FUNCTOR
#define __TB_IS_RAW_FUNCTOR 1
#include "funtion_impl_variadics.inl"
#undef __TB_PARAM_LIST
#undef __TB_PASS_PARAM_LIST
#undef __TB_PASS_PARAM_LIST_WITH_COMMA
#undef __TB_TYPEDEF_TYPES_BLOCK
#undef __TB_POP_PARAMS_BLOCK
#undef __TB_GET_PARAM_TYPE_CASES 
#undef __TB_PARAM_WITH_NAME_LIST
#undef __TB_RETRIVE_PARAM_VALUE_LIST 
#undef __TB_PASS_PARAM_VALUS_LIST 
#undef __TB_PARAM_COUNT
#undef __TB_IS_RAW_FUNCTOR
#undef __TB_VARIADICS_CLASS_PREFIX

#define __TB_PARAM_LIST , typename Param1Type, typename Param2Type, typename Param3Type, typename Param4Type, typename Param5Type, typename Param6Type
#define __TB_PASS_PARAM_LIST Param1Type, Param2Type, Param3Type, Param4Type, Param5Type, Param6Type
#define __TB_PASS_PARAM_LIST_WITH_COMMA , __TB_PASS_PARAM_LIST
#define __TB_TYPEDEF_TYPES_BLOCK __TB_TYPEDEF_PARAM_TYPE(1) __TB_TYPEDEF_PARAM_TYPE(2) __TB_TYPEDEF_PARAM_TYPE(3) __TB_TYPEDEF_PARAM_TYPE(4) __TB_TYPEDEF_PARAM_TYPE(5) __TB_TYPEDEF_PARAM_TYPE(6)
#define __TB_POP_PARAMS_BLOCK __TB_POP_PARAM(6) __TB_POP_PARAM(5) __TB_POP_PARAM(4) __TB_POP_PARAM(3) __TB_POP_PARAM(2) __TB_POP_PARAM(1)
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1) __TB_GEN_GET_PARAM_TYPE_CASE(2) __TB_GEN_GET_PARAM_TYPE_CASE(3) __TB_GEN_GET_PARAM_TYPE_CASE(4) __TB_GEN_GET_PARAM_TYPE_CASE(5) __TB_GEN_GET_PARAM_TYPE_CASE(6)
#define __TB_PARAM_WITH_NAME_LIST ,Param1Type_ *t1, Param2Type_ *t2, Param3Type_ *t3, Param4Type_ *t4, Param5Type_* t5, Param6Type_ *t6
#define __TB_RETRIVE_PARAM_VALUE_LIST *t1, *t2, *t3, *t4, *t5, *t6
#define __TB_PASS_PARAM_VALUS_LIST , t1, t2, t3, t4, t5, t6
#define __TB_PARAM_COUNT 6
#define __TB_IS_RAW_FUNCTOR 0
#define __TB_VARIADICS_CLASS_PREFIX SixParam
#include "funtion_impl_variadics.inl"
#undef __TB_IS_RAW_FUNCTOR
#define __TB_IS_RAW_FUNCTOR 1
#include "funtion_impl_variadics.inl"
#undef __TB_PARAM_LIST
#undef __TB_PASS_PARAM_LIST
#undef __TB_PASS_PARAM_LIST_WITH_COMMA
#undef __TB_TYPEDEF_TYPES_BLOCK
#undef __TB_POP_PARAMS_BLOCK
#undef __TB_GET_PARAM_TYPE_CASES 
#undef __TB_PARAM_WITH_NAME_LIST
#undef __TB_RETRIVE_PARAM_VALUE_LIST 
#undef __TB_PASS_PARAM_VALUS_LIST 
#undef __TB_PARAM_COUNT
#undef __TB_IS_RAW_FUNCTOR
#undef __TB_VARIADICS_CLASS_PREFIX

#define __TB_PARAM_LIST , typename Param1Type, typename Param2Type, typename Param3Type, typename Param4Type, typename Param5Type, typename Param6Type, typename Param7Type
#define __TB_PASS_PARAM_LIST Param1Type, Param2Type, Param3Type, Param4Type, Param5Type, Param6Type, Param7Type
#define __TB_PASS_PARAM_LIST_WITH_COMMA , __TB_PASS_PARAM_LIST
#define __TB_TYPEDEF_TYPES_BLOCK __TB_TYPEDEF_PARAM_TYPE(1) __TB_TYPEDEF_PARAM_TYPE(2) __TB_TYPEDEF_PARAM_TYPE(3) __TB_TYPEDEF_PARAM_TYPE(4) __TB_TYPEDEF_PARAM_TYPE(5) __TB_TYPEDEF_PARAM_TYPE(6) __TB_TYPEDEF_PARAM_TYPE(7)
#define __TB_POP_PARAMS_BLOCK __TB_POP_PARAM(7) __TB_POP_PARAM(6) __TB_POP_PARAM(5) __TB_POP_PARAM(4) __TB_POP_PARAM(3) __TB_POP_PARAM(2) __TB_POP_PARAM(1)
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1) __TB_GEN_GET_PARAM_TYPE_CASE(2) __TB_GEN_GET_PARAM_TYPE_CASE(3) __TB_GEN_GET_PARAM_TYPE_CASE(4) __TB_GEN_GET_PARAM_TYPE_CASE(5) __TB_GEN_GET_PARAM_TYPE_CASE(6) __TB_GEN_GET_PARAM_TYPE_CASE(7)      
#define __TB_PARAM_WITH_NAME_LIST ,Param1Type_ *t1, Param2Type_ *t2, Param3Type_ *t3, Param4Type_ *t4, Param5Type_* t5, Param6Type_ *t6, Param7Type_ *t7
#define __TB_RETRIVE_PARAM_VALUE_LIST *t1, *t2, *t3, *t4, *t5, *t6, *t7
#define __TB_PASS_PARAM_VALUS_LIST , t1, t2, t3, t4, t5, t6, t7
#define __TB_PARAM_COUNT 7
#define __TB_IS_RAW_FUNCTOR 0
#define __TB_VARIADICS_CLASS_PREFIX SevenParam
#include "funtion_impl_variadics.inl"
#undef __TB_IS_RAW_FUNCTOR
#define __TB_IS_RAW_FUNCTOR 1
#include "funtion_impl_variadics.inl"
#undef __TB_PARAM_LIST
#undef __TB_PASS_PARAM_LIST
#undef __TB_PASS_PARAM_LIST_WITH_COMMA
#undef __TB_TYPEDEF_TYPES_BLOCK
#undef __TB_POP_PARAMS_BLOCK
#undef __TB_GET_PARAM_TYPE_CASES 
#undef __TB_PARAM_WITH_NAME_LIST
#undef __TB_RETRIVE_PARAM_VALUE_LIST 
#undef __TB_PASS_PARAM_VALUS_LIST 
#undef __TB_PARAM_COUNT
#undef __TB_IS_RAW_FUNCTOR
#undef __TB_VARIADICS_CLASS_PREFIX

#undef __TB_GEN_GET_PARAM_TYPE_CASE

#undef __TB_IMPLEMENT_MEM_FUNCTION_VARIADICS

#undef __TB_PUSH_REFERENCE_PARAM
#undef __TB_POP_PARAM

} // namespace reflection

TB_NAMESPACE_END

#endif // TB_REFLECTION_REFLECTION_FUNCTION_HPP__
